Analisi cluster demografici con algoritmo non supervisionato (k-mean)

RQ: A partire dalla stratificazione del dataset per categorie demografiche, è possibile individuare cluster in relazione ai fenomeni osservati?

Filtro topic: Diabetes & Cardiovascular Disease

library(dplyr)

dataset_path <- "u_s_chronic_disease_indicators_cdi.csv"

df <- read.csv(dataset_path, na.strings = c("", "NA", "NULL", "null"))

df_filtered <- df %>%
  filter(topic %in% c("Diabetes", "Cardiovascular Disease"))

Conteggio categorie demografiche univoche

df_filtered %>%
  filter(stratificationcategory1 == "Race/Ethnicity") %>%
  count(stratification1) %>%
  arrange(desc(n))
NA

Visualizzazione question univoche

library(dplyr)

qid_map <- df_filtered %>%
  distinct(questionid, question) %>%
  arrange(questionid)

# Mostra la tabella
knitr::kable(qid_map, col.names = c("QuestionID", "Question"))
QuestionID Question
CVD10_1 Pneumococcal vaccination among noninstitutionalized adults aged 18-64 years with a history of coronary heart disease
CVD10_2 Pneumococcal vaccination among noninstitutionalized adults aged >= 65 years with a history of coronary heart disease
CVD1_1 Mortality from total cardiovascular disease
CVD1_2 Mortality from diseases of the heart
CVD1_3 Mortality from coronary heart disease
CVD1_4 Mortality from heart failure
CVD1_5 Mortality from cerebrovascular disease (stroke)
CVD2_0 Hospitalization for heart failure among Medicare-eligible persons aged >= 65 years
CVD3_1 Hospitalization for stroke
CVD3_2 Hospitalization for acute myocardial infarction
CVD4_0 Cholesterol screening among adults aged >= 18 years
CVD5_0 High cholesterol prevalence among adults aged >= 18 years
CVD6_1 Awareness of high blood pressure among adults aged >= 18 years
CVD6_2 Awareness of high blood pressure among women aged 18-44 years
CVD7_0 Taking medicine for high blood pressure control among adults aged >= 18 years with high blood pressure
CVD8_0 Pre-pregnancy hypertension
CVD9_1 Influenza vaccination among noninstitutionalized adults aged 18-64 years with a history of coronary heart disease or stroke
CVD9_2 Influenza vaccination among noninstitutionalized adults aged >= 65 years with a history of coronary heart disease or stroke
DIA10_0 Adults with diagnosed diabetes aged >= 18 years who have taken a diabetes self-management course
DIA11_1 Prevalence of high cholesterol among adults aged >= 18 years with diagnosed diabetes
DIA11_2 Prevalence of high blood pressure among adults aged >= 18 years with diagnosed diabetes
DIA11_3 Prevalence of depressive disorders among adults aged >= 18 years with diagnosed diabetes
DIA12_1 Influenza vaccination among noninstitutionalized adults aged 18-64 years with diagnosed diabetes
DIA12_2 Influenza vaccination among noninstitutionalized adults aged >= 65 years with diagnosed diabetes
DIA13_1 Pneumococcal vaccination among noninstitutionalized adults aged 18-64 years with diagnosed diabetes
DIA13_2 Pneumococcal vaccination among noninstitutionalized adults aged >= 65 years with diagnosed diabetes
DIA1_1 Mortality due to diabetes reported as any listed cause of death
DIA1_2 Mortality with diabetic ketoacidosis reported as any listed cause of death
DIA2_1 Prevalence of diagnosed diabetes among adults aged >= 18 years
DIA2_2 Diabetes prevalence among women aged 18-44 years
DIA3_1 Prevalence of pre-pregnancy diabetes
DIA3_2 Prevalence of gestational diabetes
DIA4_0 Amputation of a lower extremity attributable to diabetes
DIA5_0 Foot examination among adults aged >= 18 years with diagnosed diabetes
DIA6_0 Glycosylated hemoglobin measurement among adults aged >= 18 years with diagnosed diabetes
DIA7_0 Dilated eye examination among adults aged >= 18 years with diagnosed diabetes
DIA8_0 Visits to dentist or dental clinic among adults aged >= 18 years with diagnosed diabetes
DIA9_0 Hospitalization with diabetes as a listed diagnosis
NA

Preparazione datavalue per K-Means

library(dplyr)

# conversione in numerico di datavalue (da eventuale stringa) e gestione virgole (da , a .)
df_k <- df_filtered %>%
  mutate(
    datavalue_num = suppressWarnings(as.numeric(gsub(",", ".", datavalue, fixed = TRUE))),
    .row = dplyr::row_number()
  )

K-Means (k = 7) per ciascuna combinazione (topic, questionid, datavaluetypeid)

library(dplyr)    # gestione dati
library(purrr)    # funzioni di mappatura

set.seed(9)       # seme per riproducibilità

clustered <- df_k %>%
  group_by(topic, questionid, datavaluetypeid) %>%   # raggruppa per variabili chiave
  group_modify(~{                                   # lavora su ogni gruppo
    d <- .x                                         # sottoinsieme del gruppo
    d_non_na <- d %>% filter(!is.na(datavalue_num)) # tiene solo valori non NA

    if (nrow(d_non_na) < 7) {                       # se meno di 7 righe
      d$cluster <- NA_integer_                      # assegna NA al cluster
      d                                             # restituisce i dati così
    } else {
      km <- kmeans(d_non_na$datavalue_num,          # kmeans su 7 cluster
                   centers = 7, nstart = 25)       
      d_non_na$cluster <- km$cluster                # assegna etichette cluster

      d %>% left_join(d_non_na %>%                  # riunisce cluster con dati
                        select(.row, cluster), 
                      by = ".row")
    }
  }) %>%
  ungroup()                                         # toglie il raggruppamento

clustered %>%
  select(topic, questionid, datavaluetypeid,        # mostra colonne chiave
         datavalue_num, cluster) %>%
  head()                                            # prime righe
NA
NA

Percentuali per stratification (solo Race/Ethnicity) dentro ciascun cluster

library(dplyr)
library(tidyr)

# calcolo delle percentuali per ogni cluster e stratification
cluster_strat_pct <- clustered %>%
  # filtra solo i record con categoria race/ethnicity ed esclude cluster mancanti
  filter(stratificationcategory1 == "Race/Ethnicity", !is.na(cluster)) %>%
  # raggruppa per topic, questionid, datavaluetypeid e cluster
  group_by(topic, questionid, datavaluetypeid, cluster) %>%
  # calcola la dimensione totale del cluster
  mutate(cluster_total = n()) %>%
  # raggruppa ulteriormente per stratification1
  group_by(topic, questionid, datavaluetypeid, cluster, stratification1) %>%
  # calcola il numero di elementi per ogni combinazione
  summarise(
    n = n(),
    cluster_total = dplyr::first(cluster_total),
    .groups = "drop_last"
  ) %>%
  # calcola la percentuale di ciascuna categoria sul totale del cluster
  mutate(pct = 100 * n / cluster_total) %>%
  # rimuove i raggruppamenti
  ungroup() %>%
  # ordina i risultati
  arrange(topic, questionid, datavaluetypeid, cluster, desc(pct))

# anteprima delle prime 20 righe della tabella finale
cluster_strat_pct %>% head(20)
NA

Grafico d’esempio sulla combinazione più rappresentata

library(dplyr)   # gestione dati
library(tidyr)   # funzioni di reshaping

cluster_strat_pct <- clustered %>%
  filter(stratificationcategory1 == "Race/Ethnicity", !is.na(cluster)) %>% # tiene solo race/ethnicity e cluster validi
  group_by(topic, questionid, datavaluetypeid, cluster) %>%                # raggruppa per cluster e variabili base
  mutate(cluster_total = n()) %>%                                          # totale righe per cluster
  group_by(topic, questionid, datavaluetypeid, cluster, stratification1) %>% # aggiunge stratificazione
  summarise(
    n = n(),                                                               # conta righe per gruppo
    cluster_total = dplyr::first(cluster_total),                           # riporta totale cluster
    .groups = "drop_last"
  ) %>%
  mutate(pct = 100 * n / cluster_total) %>%                                # percentuale sul cluster
  ungroup() %>%                                                            # toglie il raggruppamento
  arrange(topic, questionid, datavaluetypeid, cluster, desc(pct))          # ordina in modo leggibile

cluster_strat_pct %>% head(20)  # anteprima prime 20 righe
NA
# crea una tabella con le combinazioni uniche di topic, questionid e datavaluetypeid ordinate
combos <- cluster_strat_pct %>%
  dplyr::distinct(topic, questionid, datavaluetypeid) %>%
  dplyr::arrange(topic, questionid, datavaluetypeid)

# ciclo per generare un grafico per ciascuna combinazione
for (i in seq_len(nrow(combos))) {
  # estrae i valori della combinazione corrente
  tp  <- combos$topic[i]
  qid <- combos$questionid[i]
  dvt <- combos$datavaluetypeid[i]
  
  # genera il grafico a torta per la combinazione corrente
  p <- plot_pies_for_combo(tp, qid, dvt)
  # stampa il grafico
  print(p)
}

LS0tCnRpdGxlOiAiQ2x1c3RlciBEZW1vZ3JhZmljaSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBBbmFsaXNpIGNsdXN0ZXIgZGVtb2dyYWZpY2kgY29uIGFsZ29yaXRtbyBub24gc3VwZXJ2aXNpb25hdG8gKGstbWVhbikKCioqUlE6KiogKkEgcGFydGlyZSBkYWxsYSBzdHJhdGlmaWNhemlvbmUgZGVsIGRhdGFzZXQgcGVyIGNhdGVnb3JpZSBkZW1vZ3JhZmljaGUsIMOoIHBvc3NpYmlsZSBpbmRpdmlkdWFyZSBjbHVzdGVyIGluIHJlbGF6aW9uZSBhaSBmZW5vbWVuaSBvc3NlcnZhdGk/KgoKIyBGaWx0cm8gdG9waWM6IERpYWJldGVzICYgQ2FyZGlvdmFzY3VsYXIgRGlzZWFzZQoKYGBge3J9CmxpYnJhcnkoZHBseXIpCgpkYXRhc2V0X3BhdGggPC0gInVfc19jaHJvbmljX2Rpc2Vhc2VfaW5kaWNhdG9yc19jZGkuY3N2IgoKZGYgPC0gcmVhZC5jc3YoZGF0YXNldF9wYXRoLCBuYS5zdHJpbmdzID0gYygiIiwgIk5BIiwgIk5VTEwiLCAibnVsbCIpKQoKZGZfZmlsdGVyZWQgPC0gZGYgJT4lCiAgZmlsdGVyKHRvcGljICVpbiUgYygiRGlhYmV0ZXMiLCAiQ2FyZGlvdmFzY3VsYXIgRGlzZWFzZSIpKQoKYGBgCgojIyMgQ29udGVnZ2lvIGNhdGVnb3JpZSBkZW1vZ3JhZmljaGUgdW5pdm9jaGUKCmBgYHtyfQpkZl9maWx0ZXJlZCAlPiUKICBmaWx0ZXIoc3RyYXRpZmljYXRpb25jYXRlZ29yeTEgPT0gIlJhY2UvRXRobmljaXR5IikgJT4lCiAgY291bnQoc3RyYXRpZmljYXRpb24xKSAlPiUKICBhcnJhbmdlKGRlc2MobikpCgpgYGAKCiMjIyBWaXN1YWxpenphemlvbmUgcXVlc3Rpb24gdW5pdm9jaGUKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQoKcWlkX21hcCA8LSBkZl9maWx0ZXJlZCAlPiUKICBkaXN0aW5jdChxdWVzdGlvbmlkLCBxdWVzdGlvbikgJT4lCiAgYXJyYW5nZShxdWVzdGlvbmlkKQoKIyBNb3N0cmEgbGEgdGFiZWxsYQprbml0cjo6a2FibGUocWlkX21hcCwgY29sLm5hbWVzID0gYygiUXVlc3Rpb25JRCIsICJRdWVzdGlvbiIpKQoKYGBgCgojIFByZXBhcmF6aW9uZSBkYXRhdmFsdWUgcGVyIEstTWVhbnMKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQoKIyBjb252ZXJzaW9uZSBpbiBudW1lcmljbyBkaSBkYXRhdmFsdWUgKGRhIGV2ZW50dWFsZSBzdHJpbmdhKSBlIGdlc3Rpb25lIHZpcmdvbGUgKGRhICwgYSAuKQpkZl9rIDwtIGRmX2ZpbHRlcmVkICU+JQogIG11dGF0ZSgKICAgIGRhdGF2YWx1ZV9udW0gPSBzdXBwcmVzc1dhcm5pbmdzKGFzLm51bWVyaWMoZ3N1YigiLCIsICIuIiwgZGF0YXZhbHVlLCBmaXhlZCA9IFRSVUUpKSksCiAgICAucm93ID0gZHBseXI6OnJvd19udW1iZXIoKQogICkKCmBgYAoKIyBLLU1lYW5zIChrID0gNykgcGVyIGNpYXNjdW5hIGNvbWJpbmF6aW9uZSAodG9waWMsIHF1ZXN0aW9uaWQsIGRhdGF2YWx1ZXR5cGVpZCkKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKSAgICAjIGdlc3Rpb25lIGRhdGkKbGlicmFyeShwdXJycikgICAgIyBmdW56aW9uaSBkaSBtYXBwYXR1cmEKCnNldC5zZWVkKDkpICAgICAgICMgc2VtZSBwZXIgcmlwcm9kdWNpYmlsaXTDoAoKY2x1c3RlcmVkIDwtIGRmX2sgJT4lCiAgZ3JvdXBfYnkodG9waWMsIHF1ZXN0aW9uaWQsIGRhdGF2YWx1ZXR5cGVpZCkgJT4lICAgIyByYWdncnVwcGEgcGVyIHZhcmlhYmlsaSBjaGlhdmUKICBncm91cF9tb2RpZnkofnsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbGF2b3JhIHN1IG9nbmkgZ3J1cHBvCiAgICBkIDwtIC54ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHNvdHRvaW5zaWVtZSBkZWwgZ3J1cHBvCiAgICBkX25vbl9uYSA8LSBkICU+JSBmaWx0ZXIoIWlzLm5hKGRhdGF2YWx1ZV9udW0pKSAjIHRpZW5lIHNvbG8gdmFsb3JpIG5vbiBOQQoKICAgIGlmIChucm93KGRfbm9uX25hKSA8IDcpIHsgICAgICAgICAgICAgICAgICAgICAgICMgc2UgbWVubyBkaSA3IHJpZ2hlCiAgICAgIGQkY2x1c3RlciA8LSBOQV9pbnRlZ2VyXyAgICAgICAgICAgICAgICAgICAgICAjIGFzc2VnbmEgTkEgYWwgY2x1c3RlcgogICAgICBkICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByZXN0aXR1aXNjZSBpIGRhdGkgY29zw6wKICAgIH0gZWxzZSB7CiAgICAgIGttIDwtIGttZWFucyhkX25vbl9uYSRkYXRhdmFsdWVfbnVtLCAgICAgICAgICAjIGttZWFucyBzdSA3IGNsdXN0ZXIKICAgICAgICAgICAgICAgICAgIGNlbnRlcnMgPSA3LCBuc3RhcnQgPSAyNSkgICAgICAgCiAgICAgIGRfbm9uX25hJGNsdXN0ZXIgPC0ga20kY2x1c3RlciAgICAgICAgICAgICAgICAjIGFzc2VnbmEgZXRpY2hldHRlIGNsdXN0ZXIKCiAgICAgIGQgJT4lIGxlZnRfam9pbihkX25vbl9uYSAlPiUgICAgICAgICAgICAgICAgICAjIHJpdW5pc2NlIGNsdXN0ZXIgY29uIGRhdGkKICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KC5yb3csIGNsdXN0ZXIpLCAKICAgICAgICAgICAgICAgICAgICAgIGJ5ID0gIi5yb3ciKQogICAgfQogIH0pICU+JQogIHVuZ3JvdXAoKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyB0b2dsaWUgaWwgcmFnZ3J1cHBhbWVudG8KCmNsdXN0ZXJlZCAlPiUKICBzZWxlY3QodG9waWMsIHF1ZXN0aW9uaWQsIGRhdGF2YWx1ZXR5cGVpZCwgICAgICAgICMgbW9zdHJhIGNvbG9ubmUgY2hpYXZlCiAgICAgICAgIGRhdGF2YWx1ZV9udW0sIGNsdXN0ZXIpICU+JQogIGhlYWQoKSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBwcmltZSByaWdoZQoKCmBgYAoKIyBQZXJjZW50dWFsaSBwZXIgc3RyYXRpZmljYXRpb24gKHNvbG8gUmFjZS9FdGhuaWNpdHkpIGRlbnRybyBjaWFzY3VuIGNsdXN0ZXIKCmBgYHtyfQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KHRpZHlyKQoKIyBjYWxjb2xvIGRlbGxlIHBlcmNlbnR1YWxpIHBlciBvZ25pIGNsdXN0ZXIgZSBzdHJhdGlmaWNhdGlvbgpjbHVzdGVyX3N0cmF0X3BjdCA8LSBjbHVzdGVyZWQgJT4lCiAgIyBmaWx0cmEgc29sbyBpIHJlY29yZCBjb24gY2F0ZWdvcmlhIHJhY2UvZXRobmljaXR5IGVkIGVzY2x1ZGUgY2x1c3RlciBtYW5jYW50aQogIGZpbHRlcihzdHJhdGlmaWNhdGlvbmNhdGVnb3J5MSA9PSAiUmFjZS9FdGhuaWNpdHkiLCAhaXMubmEoY2x1c3RlcikpICU+JQogICMgcmFnZ3J1cHBhIHBlciB0b3BpYywgcXVlc3Rpb25pZCwgZGF0YXZhbHVldHlwZWlkIGUgY2x1c3RlcgogIGdyb3VwX2J5KHRvcGljLCBxdWVzdGlvbmlkLCBkYXRhdmFsdWV0eXBlaWQsIGNsdXN0ZXIpICU+JQogICMgY2FsY29sYSBsYSBkaW1lbnNpb25lIHRvdGFsZSBkZWwgY2x1c3RlcgogIG11dGF0ZShjbHVzdGVyX3RvdGFsID0gbigpKSAlPiUKICAjIHJhZ2dydXBwYSB1bHRlcmlvcm1lbnRlIHBlciBzdHJhdGlmaWNhdGlvbjEKICBncm91cF9ieSh0b3BpYywgcXVlc3Rpb25pZCwgZGF0YXZhbHVldHlwZWlkLCBjbHVzdGVyLCBzdHJhdGlmaWNhdGlvbjEpICU+JQogICMgY2FsY29sYSBpbCBudW1lcm8gZGkgZWxlbWVudGkgcGVyIG9nbmkgY29tYmluYXppb25lCiAgc3VtbWFyaXNlKAogICAgbiA9IG4oKSwKICAgIGNsdXN0ZXJfdG90YWwgPSBkcGx5cjo6Zmlyc3QoY2x1c3Rlcl90b3RhbCksCiAgICAuZ3JvdXBzID0gImRyb3BfbGFzdCIKICApICU+JQogICMgY2FsY29sYSBsYSBwZXJjZW50dWFsZSBkaSBjaWFzY3VuYSBjYXRlZ29yaWEgc3VsIHRvdGFsZSBkZWwgY2x1c3RlcgogIG11dGF0ZShwY3QgPSAxMDAgKiBuIC8gY2x1c3Rlcl90b3RhbCkgJT4lCiAgIyByaW11b3ZlIGkgcmFnZ3J1cHBhbWVudGkKICB1bmdyb3VwKCkgJT4lCiAgIyBvcmRpbmEgaSByaXN1bHRhdGkKICBhcnJhbmdlKHRvcGljLCBxdWVzdGlvbmlkLCBkYXRhdmFsdWV0eXBlaWQsIGNsdXN0ZXIsIGRlc2MocGN0KSkKCiMgYW50ZXByaW1hIGRlbGxlIHByaW1lIDIwIHJpZ2hlIGRlbGxhIHRhYmVsbGEgZmluYWxlCmNsdXN0ZXJfc3RyYXRfcGN0ICU+JSBoZWFkKDIwKQoKYGBgCgojIEdyYWZpY28gZOKAmWVzZW1waW8gc3VsbGEgY29tYmluYXppb25lIHBpw7kgcmFwcHJlc2VudGF0YQoKYGBge3J9CmxpYnJhcnkoZHBseXIpICAgIyBnZXN0aW9uZSBkYXRpCmxpYnJhcnkodGlkeXIpICAgIyBmdW56aW9uaSBkaSByZXNoYXBpbmcKCmNsdXN0ZXJfc3RyYXRfcGN0IDwtIGNsdXN0ZXJlZCAlPiUKICBmaWx0ZXIoc3RyYXRpZmljYXRpb25jYXRlZ29yeTEgPT0gIlJhY2UvRXRobmljaXR5IiwgIWlzLm5hKGNsdXN0ZXIpKSAlPiUgIyB0aWVuZSBzb2xvIHJhY2UvZXRobmljaXR5IGUgY2x1c3RlciB2YWxpZGkKICBncm91cF9ieSh0b3BpYywgcXVlc3Rpb25pZCwgZGF0YXZhbHVldHlwZWlkLCBjbHVzdGVyKSAlPiUgICAgICAgICAgICAgICAgIyByYWdncnVwcGEgcGVyIGNsdXN0ZXIgZSB2YXJpYWJpbGkgYmFzZQogIG11dGF0ZShjbHVzdGVyX3RvdGFsID0gbigpKSAlPiUgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRvdGFsZSByaWdoZSBwZXIgY2x1c3RlcgogIGdyb3VwX2J5KHRvcGljLCBxdWVzdGlvbmlkLCBkYXRhdmFsdWV0eXBlaWQsIGNsdXN0ZXIsIHN0cmF0aWZpY2F0aW9uMSkgJT4lICMgYWdnaXVuZ2Ugc3RyYXRpZmljYXppb25lCiAgc3VtbWFyaXNlKAogICAgbiA9IG4oKSwgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNvbnRhIHJpZ2hlIHBlciBncnVwcG8KICAgIGNsdXN0ZXJfdG90YWwgPSBkcGx5cjo6Zmlyc3QoY2x1c3Rlcl90b3RhbCksICAgICAgICAgICAgICAgICAgICAgICAgICAgIyByaXBvcnRhIHRvdGFsZSBjbHVzdGVyCiAgICAuZ3JvdXBzID0gImRyb3BfbGFzdCIKICApICU+JQogIG11dGF0ZShwY3QgPSAxMDAgKiBuIC8gY2x1c3Rlcl90b3RhbCkgJT4lICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHBlcmNlbnR1YWxlIHN1bCBjbHVzdGVyCiAgdW5ncm91cCgpICU+JSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgdG9nbGllIGlsIHJhZ2dydXBwYW1lbnRvCiAgYXJyYW5nZSh0b3BpYywgcXVlc3Rpb25pZCwgZGF0YXZhbHVldHlwZWlkLCBjbHVzdGVyLCBkZXNjKHBjdCkpICAgICAgICAgICMgb3JkaW5hIGluIG1vZG8gbGVnZ2liaWxlCgpjbHVzdGVyX3N0cmF0X3BjdCAlPiUgaGVhZCgyMCkgICMgYW50ZXByaW1hIHByaW1lIDIwIHJpZ2hlCgpgYGAKCmBgYHtyfQpjb21ib3MgPC0gY2x1c3Rlcl9zdHJhdF9wY3QgJT4lCiAgZHBseXI6OmRpc3RpbmN0KHRvcGljLCBxdWVzdGlvbmlkLCBkYXRhdmFsdWV0eXBlaWQpICU+JSAgICMgY29tYmluYXppb25pIHVuaWNoZQogIGRwbHlyOjphcnJhbmdlKHRvcGljLCBxdWVzdGlvbmlkLCBkYXRhdmFsdWV0eXBlaWQpICAgICAgICAjIG9yZGluYXRlCgpmb3IgKGkgaW4gc2VxX2xlbihucm93KGNvbWJvcykpKSB7ICAgICAgICAgICAgICAgICAgICAgICAgICAjIGNpY2xvIHN1bGxlIGNvbWJpbmF6aW9uaQogIHRwICA8LSBjb21ib3MkdG9waWNbaV0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIHRvcGljIGNvcnJlbnRlCiAgcWlkIDwtIGNvbWJvcyRxdWVzdGlvbmlkW2ldICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgcXVlc3Rpb25pZCBjb3JyZW50ZQogIGR2dCA8LSBjb21ib3MkZGF0YXZhbHVldHlwZWlkW2ldICAgICAgICAgICAgICAgICAgICAgICAgICAjIHR5cGVpZCBjb3JyZW50ZQogIAogIHAgPC0gcGxvdF9waWVzX2Zvcl9jb21ibyh0cCwgcWlkLCBkdnQpICAgICAgICAgICAgICAgICAgICAjIGdlbmVyYSBpbCBncmFmaWNvCiAgcHJpbnQocCkgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgbW9zdHJhIGlsIGdyYWZpY28KfQoKfQpgYGAK